//@author A0100965J
package memory;

import java.util.Stack;

import common.Command;


/**
 * This provides the service for the full History
 */
public class History {
	private Stack<Command> _beforePointer;
	private Stack<Command> _afterPointer;
	private static History _history;
	/**
	 * Constructor which creates a new list of commandHistory when user opens
	 * the application
	 */
	public History() {
		_beforePointer = new Stack<Command>();
		_afterPointer = new Stack<Command>();
	}
	
	public static History getInstance() {
		if (_history == null) {
			_history = new History();
		}
		return _history;
	}

	/**
	 * This will return the nearest ExecutableCommand 
	 * ExecutableCommand = command of type: create, update, delete, mark, block, etc
	 * 
	 * @return the latest Executable Command / null when nothing found
	 */
	public Command undo() {
		// Pop from History and Push to the other stack until get the first
		// Executable Command
		Command cmd = null;
		while (!_beforePointer.isEmpty()) {
			cmd = _beforePointer.pop();
			if (cmd.isExecutable()) {
				_afterPointer.push(cmd);
				break;
			} else {
				_afterPointer.push(cmd);
			}
		}

		// Push back popped items in the temporary stack
		while (!_afterPointer.isEmpty()) {
			_beforePointer.push(_afterPointer.pop());
		}

		return cmd;
	}

	/**
	 * This will return the latest Command This is called by Command Recall
	 * 
	 * @return the latest Command
	 */
	public Command recallCmd() {
		if (!_beforePointer.isEmpty()) {
			return _beforePointer.peek();
		} else {
			return null;
		}
	}

	/**
	 * Remove all the commands after the pointer and Push the new command to the
	 * stack Pointer resets to the top of the stack
	 * 
	 * @param newCommand
	 *           
	 */
	public void pushCmd(Command newCommand) {
		_beforePointer.push(newCommand);
	}
	
	/**
	 * Move pointer to the command before the current pointer
	 * @return 
	 */
	public Command movePointerBack() {
		if (!_beforePointer.empty()) {
			_afterPointer.push(_beforePointer.pop());
			return _afterPointer.peek();
		} else {
			return null;
		}
	}
	
	/**
	 * Move pointer to the command after the current pointer
	 * @return
	 */
	public Command movePointerFront() {
		if (!_afterPointer.empty()) {
			_beforePointer.push(_afterPointer.pop());
			if (!_afterPointer.empty()) {
				return _afterPointer.peek();
			}
		} 
		return null;
	}
	
	/**
	 * Restore the position of pointer back to the top of command stack
	 */
	public void restorePointer() {
		while (!_afterPointer.empty()) {
			_beforePointer.push(_afterPointer.pop());
		}
	}
	
}
